#include "BrushGuard.h"
#include "Character/monster/MonsterMgr.h"
#include "Character/monster/MonsterRefCfg.h"
#include "Duplicate/IDuplicate.h"
#include "Character/CreatureMgr.h"
#include "Character/newAI/behaviac/CreatureCommonAI.h"

BrushGuard::BrushGuard() :m_pDuplicate(nullptr), m_pBrush(nullptr), m_nWave(0), m_startWaveTime(0), m_waveCd(0)
{
	m_bBrushFinish = false;
	m_bStart = false;
	m_setBrushMons.clear();
	m_tipIdx = -1;
}

BrushGuard::~BrushGuard()
{

}

bool BrushGuard::Init(IDuplicate *pDuplicate)
{
	if (nullptr == pDuplicate)
	{
		LogErrFmtPrint("BrushGuard::Init...nullptr == pDuplicate");
		return false;
	}
	m_pDuplicate = pDuplicate;
	AllBrushDataCfg *pAllBrush = m_pDuplicate->GetBrushData();
	if (nullptr == pAllBrush)
	{
		LogErrFmtPrint("BrushGuard::Init...nullptr == pAllBrush,scene:%u,dup:%u ",pDuplicate->GetSceneID(),pDuplicate->GetDuplicateID());
		return false;
	}
	m_pBrush = &pAllBrush->stGuard;
	return true;
}

void BrushGuard::UnInit()
{
	g_GetTimerAxis()->KillAllTimer(this);
	m_pDuplicate = nullptr;
	m_pBrush = nullptr;
	m_bStart = false;
	m_bBrushFinish = false;
	m_nWave = 0;
	m_startWaveTime = 0;
	m_waveCd = 0;
	m_setBrushMons.clear();
	m_tipIdx = -1;
}

void BrushGuard::StartBrush()
{
	m_bStart = true;
	InitTimeBrush();
}

void BrushGuard::StopBrush()
{
	m_bStart = false;
	m_bBrushFinish = true;
	g_GetTimerAxis()->KillAllTimer(this);
}

//是否刷怪完成
bool BrushGuard::FinishBrush()
{
	return m_bBrushFinish;
}

void BrushGuard::BrushUpdate()
{
	if (m_bBrushFinish)
		return;
	if (nullptr == m_pBrush)
	{
		LogErrFmtPrint("BrushGuard::BrushUpdate...nullptr == m_pBrush");
		return;
	}
	CheckMonsEnterArea();
	if (m_pBrush->brushFinish())
		m_bBrushFinish = true;
}

void BrushGuard::OnTimer(uint32_t nTimerID)
{
	if (0 == nTimerID)
	{
		if (m_tipIdx >= 0)
		{
			if (nullptr != m_pBrush)
			{
				if (m_tipIdx < (int32_t)m_pBrush->vecAllTimeBrush.size())
				{
					TimeBrushCfg &stBrush = m_pBrush->vecAllTimeBrush.at(m_tipIdx);
					Duplicate_NotifyTipsRsp rsp;
					rsp.set_type(stBrush.tipType);
					rsp.set_sec(stBrush.lastSec);
					rsp.set_tip_id(stBrush.tipId);
					m_pDuplicate->BroadCastData(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_NOTIFY_TIPS, &rsp);
				}
			}
			else
			{
				LogErrFmtPrint("BrushGuard::OnTimer...nullptr == m_pBrush timerid:%d,tipid:%d", nTimerID, m_tipIdx);
			}			
		}
		m_tipIdx = -1;
	}
	else
	{
		TimeBrush(nTimerID);
	}
}

void BrushGuard::OnMonterDead(uint64_t monsCid, uint32_t monsId, uint32_t count, int32_t formationId ,uint64_t killerCid)
{
	if (nullptr == m_pBrush)
	{
		LogErrFmtPrint("[logic] BrushGuard::OnMonterDead....nullptr == m_pBrush....monsCid:%lu, monsId:%u, count:%u, formationId:%u,killercid:%lu ", monsCid, monsId, count, formationId, killerCid);
		return;
	}
	//从已刷新的怪物中移除
	m_setBrushMons.erase(monsCid);
	//
	MAP_UINT32_UINT32::iterator iter = m_pBrush->mapAllTimeMonster.find(monsId);
	if (iter != m_pBrush->mapAllTimeMonster.end())
	{
		if (iter->second > 0)
		{
			iter->second -= 1;
		}
		if (iter->second == 0)
		{
			m_pBrush->mapAllTimeMonster.erase(iter);
		}
	}
}

//脚本刷出的怪是否全部死亡
bool BrushGuard::BrushMonsAllDie()
{
	if (FinishBrush())
	{
		return (0 == m_setBrushMons.size());
	}
	return false;
}

//获取刷怪定时器ID
int32_t BrushGuard::GetTidByIdx(int32_t idx1, int32_t idx2)
{
	int32_t tid = 0;
	unsigned char *p = (unsigned char*)&tid;
	*p = idx1;
	*(p + 1) = idx2;
	return tid;
}
//获取索引
void BrushGuard::GetIdxByTid(int32_t tid, int32_t &idx1, int32_t &idx2)
{
	unsigned char *p = (unsigned char*)&tid;
	idx1 = *p;
	idx2 = *(p + 1);
}

//初始化定时刷怪
void BrushGuard::InitTimeBrush()
{
	if (nullptr == m_pBrush)
	{
		LogErrFmtPrint("BrushGuard::InitTimeBrush....nullptr == m_pBrush...");
		return;
	}
	/*
	小组索引，子项索引 每个索引1个字节
	*/
	int32_t nGroupCnt = m_pBrush->vecAllTimeBrush.size();

	if (nGroupCnt > 0)
	{
		int32_t i = 0;
		TimeBrushCfg &stFix = m_pBrush->vecAllTimeBrush.at(i);
		int32_t nSubCnt = stFix.vecBrushCfg.size();
		for (int32_t j = 0; j < nSubCnt; ++j)
		{
			//TimeBrushCfgInfo &stMons = stFix.vecBrushCfg.at(idx);
			int32_t idx1 = i + 1; //小组索引
			int32_t idx2 = j + 1;  //子项索引
			int32_t nTimerID = GetTidByIdx(idx1, idx2);
			LogDebugFmtPrint("[logic] BrushGuard::InitTimeBrush...nTimerID:%d ,idx1:%d,idx2:%d, ", nTimerID, idx1, idx2);
			int32_t nInitDelay = ((m_pBrush->nInitDelay == 0) ? 500 : m_pBrush->nInitDelay * 1000);
			g_GetTimerAxis()->SetTimer(nTimerID, nInitDelay, this, 1);
		}

		m_nWave = 1;
		m_startWaveTime = g_GetGlobalServerTime()->UnixSec();
		m_waveCd = m_pBrush->nInitDelay;
		//LogDebugFmtPrint("[logic] init BrushGuard 11...wave:%d, cd:%d  ", m_nWave, m_waveCd);
		NotifyMonsWave();

		if (stFix.isOpen)
		{
			m_tipIdx = i;
			int32_t millsec = (stFix.beginSec <= 0) ? 500 : (stFix.beginSec * 1000);
			g_GetTimerAxis()->KillTimer(0, this);
			g_GetTimerAxis()->SetTimer(0, millsec, this, 1);
		}
	}
}
//定时刷怪
void BrushGuard::TimeBrush(int32_t nTimerID)
{
	if (m_bBrushFinish)
	{
		return;
	}
	if (nullptr == m_pBrush)
	{
		LogErrFmtPrint("BrushGuard::TimeBrush...nullptr == m_pBrush...timerid:%d ", nTimerID);
		return;
	}
	if (nullptr == m_pDuplicate)
	{
		LogErrFmtPrint("BrushGuard::TimeBrush...nullptr == m_pDuplicate...timerid:%d ", nTimerID);
		return;
	}
	int32_t idx1 = 0;
	int32_t idx2 = 0;
	GetIdxByTid(nTimerID, idx1, idx2);
	int32_t new_idx1 = idx1;
	int32_t new_idx2 = idx2;
	idx1 -= 1; //小组索引
	idx2 -= 1; //子项索引
	if (idx1 < 0 || idx2 < 0)
	{
		return;
	}
	if ((uint32_t)idx1 >= m_pBrush->vecAllTimeBrush.size())
	{
		return;
	}
	TimeBrushCfg &stBrush = m_pBrush->vecAllTimeBrush.at(idx1);
	if ((uint32_t)idx2 >= stBrush.vecBrushCfg.size())
	{
		return;
	}
	TimeBrushCfgInfo &stMons = stBrush.vecBrushCfg.at(idx2);
	if (stMons.nNum > 0)
	{
		//这里创建怪物
		Point3<float> pos = g_GetMapLocationCfg()->RandPosInArea(stMons.nAreaID);
		MonsCreateParam createParam;
		createParam.createType = EMonsCreateType_Dup;
		createParam.createTypeVal = m_pDuplicate->GetDuplicateID();
		Monster *pMonster = g_GetCreatureMgr()->CreateMonster(stMons.nMonsID, m_pDuplicate->GetSceneID(), pos, createParam);
		if (nullptr != pMonster)
		{
			m_setBrushMons.insert(pMonster->GetCid());
			if (stMons.nLineId > 0)
			{
				const PathRefLocation *pPathLoc = g_GetMapLocationCfg()->GetPathRefLoc(stMons.nLineId);
				if (nullptr != pPathLoc)
				{
					pMonster->SetAiPath(stMons.nLineId, ENUM_MONSTER_PATROL_TYPE_ONE_WAY_TRIP);
				}
			}
			LogDebugFmtPrint("[logic] BrushGuard::TimeBrush...duplicateid:%u,sceneid:%u ,  monsid:%u,[%f,%f,%f] , [%d,%d] ..", m_pDuplicate->GetDuplicateID(), m_pDuplicate->GetSceneID(), stMons.nMonsID, pos.x, pos.y, pos.z, new_idx1, new_idx2);
		}
		else
		{
			LogErrFmtPrint("[logic] BrushGuard::TimeBrush error...duplicateid:%u,sceneid:%u , monsid:%u, [%f,%f,%f], [%d,%d] ..", m_pDuplicate->GetDuplicateID(), m_pDuplicate->GetSceneID(), stMons.nMonsID, pos.x, pos.y, pos.z, new_idx1, new_idx2);
		}

		
		//数量减1
		stMons.nNum -= 1;
		if (stMons.nNum > 0)
		{
			//设置下一次刷新的定时器
			int32_t nBornDelay = ((stMons.nBornDelay == 0) ? 500 : stMons.nBornDelay * 1000);
			g_GetTimerAxis()->KillTimer(nTimerID, this);
			g_GetTimerAxis()->SetTimer(nTimerID, nBornDelay, this, 1);
		}
		else if (m_nWave < (int32_t)m_pBrush->vecAllTimeBrush.size()) //不是最后一波
		{
			//一小波怪物刷完了 ，检测当前小组怪物列表是否已经全部刷完
			//如果刷完了，需要刷下一大波的怪物
			bool bFlag = true;
			VecTimeBrushCfg::iterator iterCheck = stBrush.vecBrushCfg.begin();
			for (; iterCheck != stBrush.vecBrushCfg.end(); ++iterCheck)
			{
				TimeBrushCfgInfo &stOld = (*iterCheck);
				if (stOld.nNum > 0)
				{
					bFlag = false;
					break;
				}
			}
			if (bFlag) //上一大波已经刷完了，
			{
				int32_t ex_idx1 = idx1 + 1;
				new_idx1 = ex_idx1 + 1;
				//新的小组怪物列表
				TimeBrushCfg &stNewMon = m_pBrush->vecAllTimeBrush.at(ex_idx1);
				int32_t ex_len = stNewMon.vecBrushCfg.size();
				for (int32_t k = 0; k < ex_len; ++k)
				{
					new_idx2 = k + 1;
					int32_t nNewTimerID = GetTidByIdx(new_idx1, new_idx2);
					int32_t nInter = ((m_pBrush->nInterSec == 0) ? 500 : m_pBrush->nInterSec * 1000);
					//设置新的小组开始刷怪的定时器
					g_GetTimerAxis()->KillTimer(nNewTimerID, this);
					g_GetTimerAxis()->SetTimer(nNewTimerID, nInter, this, 1);
				}
				//下一波
				m_nWave += 1;
				m_startWaveTime = g_GetGlobalServerTime()->UnixSec();
				m_waveCd = m_pBrush->nInterSec;
				//LogDebugFmtPrint("[logic] BrushGuard 11...wave:%d, cd:%d  ", m_nWave, m_waveCd);
				NotifyMonsWave();


				//注册前端tip提示定时器
				if (stNewMon.isOpen)
				{
					m_tipIdx = ex_idx1;
					int32_t millsec = (stNewMon.beginSec <= 0) ? 500 : (stNewMon.beginSec * 1000);
					g_GetTimerAxis()->KillTimer(0, this);
					g_GetTimerAxis()->SetTimer(0, millsec, this, 1);
				}
			}
		}
	}
}


void BrushGuard::NotifyMonsWave()
{
	if (nullptr != m_pDuplicate)
	{
		Duplicate_MonsWaveRsp rsp;
		rsp.set_wave(m_nWave);
		rsp.set_sec(m_waveCd);
		m_pDuplicate->BroadCastData(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_MONSTER_WAVE, &rsp);
	}
}


void BrushGuard::CheckMonsEnterArea()
{
	if (nullptr == m_pDuplicate || nullptr == m_pBrush || !m_bStart || m_bBrushFinish)
	{
		return;
	}
	MonsEnterAreaCfgData &stMonsEnterArea = m_pBrush->stMonsEnterArea;
	if (stMonsEnterArea.mapMonsEnterAreaBrush.size() <= 0 && stMonsEnterArea.vecMonsEnterAreaFight.size() <= 0)
	{
		return;
	}
	uint32_t sceneId = m_pDuplicate->GetSceneID();
	uint32_t mapId = m_pDuplicate->GetMapID();
	Scene *pScene = g_GetSceneMgr()->GetScene(sceneId);
	if (nullptr == pScene)
	{
		LogErrFmtPrint("[logic] BrushGuard::CheckMonsEnterArea...nullptr == pScene...sceneid:%u ", sceneId);
		return;
	}
	//校验走进区域该改变战斗方式
	VecMonsEnterAreaFightCfg::iterator iterFight = stMonsEnterArea.vecMonsEnterAreaFight.begin();
	for (; iterFight != stMonsEnterArea.vecMonsEnterAreaFight.end(); ++iterFight)
	{
		MonsEnterAreaFightCfgInfo &fightInfo = (*iterFight);
		MAP_UINT32_SET_UINT64 mapGroupMons;
		mapGroupMons.clear();
		m_pDuplicate->GetMonsByGroup(fightInfo.setMonsTid, mapGroupMons);
		MAP_UINT32_SET_UINT64::iterator iter = mapGroupMons.begin();
		for (; iter != mapGroupMons.end(); ++iter)
		{
			SET_UINT64 &setMons = iter->second;
			SET_UINT64::iterator iterMons = setMons.begin();
			for (; iterMons != setMons.end(); ++iterMons)
			{
				uint64_t monsCid = (*iterMons);
				Monster *pMonster = pScene->GetMonster(monsCid);
				if (nullptr == pMonster)
				{
					m_setEnterAreaFight.insert(monsCid);
					continue;
				}
				SET_UINT64::iterator iterAlreday = m_setEnterAreaFight.find(monsCid);
				if (iterAlreday != m_setEnterAreaFight.end())
				{
					continue;
				}

				Point3<float> pos = pMonster->GetPos();
				if (pScene->InArea(fightInfo.areaId, pos))
				{
					m_setEnterAreaFight.insert(monsCid);
					//进去区域了，改变战斗方式
					CreatureCommonAI *pAi = pMonster->GetAiData();
					if (nullptr != pAi)
					{
						pAi->SetAttackType(fightInfo.toFightType);
					}
				}
			}
		}
	}

	//进入区域刷怪
	SET_UINT32 setDelBrush;
	setDelBrush.clear();
	MapMonsEnterAreaBrushCfg::iterator iterBrush = stMonsEnterArea.mapMonsEnterAreaBrush.begin();
	for (; iterBrush != stMonsEnterArea.mapMonsEnterAreaBrush.end(); ++iterBrush)
	{
		MonsEnterAreaBrushCfgInfo &brushInfo = iterBrush->second;
		Monster *pMonster = pScene->GetMonsterByCfgId(brushInfo.monsId);
		if (nullptr == pMonster)
		{
			continue;
		}

		Point3<float> pos = pMonster->GetPos();
		if (!pScene->InArea(brushInfo.areaId, pos))
		{
			continue;
		}
		setDelBrush.insert(brushInfo.monsId);
		//刷新怪物
		SET_INT32::iterator iterTid = brushInfo.setTid.begin();
		for (; iterTid != brushInfo.setTid.end(); ++iterTid)
		{
			uint32_t tid = (*iterTid);
			const std::vector<MonsterRefLocation>* pVecMonsRefLoc = g_GetMapLocationCfg()->GetMapGroupMonster(mapId, tid);
			if (nullptr == pVecMonsRefLoc)
			{
				continue;
			}
			//
			std::vector<MonsterRefLocation>::const_iterator iterLoc = pVecMonsRefLoc->begin();
			for (; iterLoc != pVecMonsRefLoc->end(); ++iterLoc)
			{
				const MonsterRefLocation &refLoc = (*iterLoc);
				Point3<float> dir(0, 0, 1);
				MonsCreateParam createParam;
				createParam.createType = EMonsCreateType_Dup;
				createParam.createTypeVal = m_pDuplicate->GetDuplicateID();
				Monster *pNewMonster = g_GetCreatureMgr()->CreateMonster(refLoc.m_id, sceneId, refLoc.m_bornPos, createParam, dir, refLoc.m_RefLocIndex, nullptr, 0, refLoc.m_group);
				if (nullptr != pNewMonster)
				{
					LogDebugFmtPrint("[logic] BrushGuard::CheckMonsEnterArea...dupid:%u, sceneid:%u, mapid:%u, monsid:%u,,monsCid:%lu, pos:%f,%f,%f ", m_pDuplicate->GetDuplicateID(), sceneId, mapId, refLoc.m_id, pNewMonster->GetCid(), refLoc.m_bornPos.x, refLoc.m_bornPos.y, refLoc.m_bornPos.z);
				}
				else
				{
					LogErrFmtPrint("[logic] BrushGuard::CheckMonsEnterArea....nullptr == pNewMonster...dupid:%u, sceneid:%u, mapid:%u, monsid:%u, pos:%f,%f,%f ", m_pDuplicate->GetDuplicateID(), sceneId, mapId, refLoc.m_id, refLoc.m_bornPos.x, refLoc.m_bornPos.y, refLoc.m_bornPos.z);
				}
			}
		}
	}
	SET_UINT32::iterator iterDel = setDelBrush.begin();
	for (; iterDel != setDelBrush.end(); ++iterDel)
	{
		stMonsEnterArea.mapMonsEnterAreaBrush.erase((*iterDel));
	}
}
